package br.ufrj.dcc.tp.cliente.model;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.List;

import br.ufrj.dcc.tp.cliente.controller.ClientController;
import br.ufrj.dcc.tp.utils.Config;
import br.ufrj.dcc.tp.utils.interfaces.ISocketMessage;

/***
 * Classe que trata os eventos que o servidor chama no cliente:
 * Evento de Atualizar lista de usuarios. Ocorre sempre que um usuario novo conecta.
 * Evento de recebimento de mensagem. Ocorre sempre que alguem enviar uma mensagem
 * para esse destinatario.
 * @author wakim
 */
public class ClientNotifier extends Thread {
	private Socket socket;
	private ObjectInputStream in;
	private ClientController controller;
	private boolean closed = false;
	
	public ClientNotifier(ClientController controller, Socket socket, ObjectInputStream in) {
		this.socket = socket;
		this.in = in;
		this.controller = controller;
	}
	
	@Override
	public void run() {
		
		try {
			// Seta um timeout para a thread poder atender interrupcoes.
			socket.setSoTimeout(Config.IO_READ_TIMEOUT.toInteger());
			
			ISocketMessage message = null;
			closed = false;
			while( ! isInterrupted() ) {
				try {
					message = null;
					Object obj = null;
					
					synchronized (socket) {
						if( socket != null && ! socket.isOutputShutdown() && ! socket.isClosed() ) {
							obj = in.readObject();
						}
					}
					
					if( obj != null && ( obj instanceof ISocketMessage ) ) {
						message = (ISocketMessage) obj;
						
						switch(message.getAction()) {
							case SEND_MESSAGE:
								processSendMessageAction(message);
								break;
							case LIST_USERS:
								processListUsersAction(message);
								break;
							case CLOSE:
								close();
								break;
							default: // CREATE OU ASSOCIATE nao faz sentido nesse contexto.
								break;
						}
					}
				} catch( InterruptedIOException e ) {
				}
				
				try {
					Thread.sleep(Config.SLEEP_TIMEOUT.toInteger());
				} catch( InterruptedException e ) {
					break;
				}
			}
		} catch (IOException e) {
			close();
		} catch(ClassNotFoundException e) {	
			close();
		}
	}
	
	private void close() {
		if( ! closed ) {
			closed = true;
			controller.serverDisconnected();
		}
	}
	
	@SuppressWarnings("unchecked")
	private void processListUsersAction(ISocketMessage message) {
		if( message.getBody() != null &&
			message.getBody() instanceof List<?>
		) {
			controller.updateRecipientsList((List<String>)message.getBody());
		}
	}
	
	private void processSendMessageAction(ISocketMessage message) {
		if( message.getBody() != null ) {
			controller.appendMessage(message.getBody().toString());
		}
	}
}
